from __future__ import print_function

from kharlia import core, engine

import wx
from wx import glcanvas

# Translations from wx keys to local engine (CEGUI based) keycodes
GKeyTranslations = {
    wx.WXK_LEFT: engine.KEY_ARROW_LEFT,
    wx.WXK_RIGHT: engine.KEY_ARROW_RIGHT,
    wx.WXK_DOWN: engine.KEY_ARROW_DOWN,
    wx.WXK_UP: engine.KEY_ARROW_UP
    }

class CViewport(glcanvas.GLCanvas, engine.CClientViewport):
    def __init__(self, *args, **kwds):
        glcanvas.GLCanvas.__init__(self, *args, **kwds)
        self.Size = None
        self.Resizing = False
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftMouseDown)
        self.Bind(wx.EVT_LEFT_UP, self.OnLeftMouseUp)
        self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightMouseDown)
        self.Bind(wx.EVT_RIGHT_UP, self.OnRightMouseUp)
        self.Bind(wx.EVT_MOTION, self.OnMouseMotion)
        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
        self.KeyDownEvent = core.FEvent()
        self.KeyUpEvent = core.FEvent()
        self.XHandle = self.GetHandle()
        self.Engine = None
        self.Client = None
    
    def __del__(self):
        self._ClearWindowHandle()
        super(CViewport, self).__del__()

    # CClientViewport interface
    
    def GetWindowHandle(self):
        return self.XHandle
    
    def CheckWindowHandle(self):
        return True
    
    def OnClientInited(self, client):
        self.Client = client
        self.Engine = client.Engine
        
    def OnClientExiting(self):
        self.Client = None
        self.Engine = None
    
    # end CClientViewport interface
    
    def _ClearWindowHandle(self):
        if (self.Client is not None and
            self.Client.WindowHandle == self.XHandle):
            self.Engine.FiniClient()

    def Destroy(self):
        self._ClearWindowHandle()
        super(CViewport, self).Destroy()

    def OnKeyDown(self, event):
        cl = self.Client
        if cl is not None:
            ecode = GKeyTranslations.get(event.GetKeyCode(), None)
            if ecode is not None:
                state = cl.IsKeyPressed(ecode)
                cl.InputKeyDown(ecode)
                if state != cl.IsKeyPressed(ecode):
                    self.OnKeyDownFirst(event, ecode)
        self.KeyDownEvent(self, event)
        
    def OnKeyDownFirst(self, event, ecode):
        if self.Engine.TestMovement:
            if ecode == engine.KEY_ARROW_LEFT:
                self.Engine.TestMovement.Velocity.X -= 8.0
            elif ecode == engine.KEY_ARROW_RIGHT:
                self.Engine.TestMovement.Velocity.X += 8.0
            elif ecode == engine.KEY_ARROW_DOWN:
                self.Engine.TestMovement.Velocity.Y += 8.0
            elif ecode == engine.KEY_ARROW_UP:
                self.Engine.TestMovement.Velocity.Y -= 8.0

    def OnKeyUp(self, event):
        if self.Client is not None:
            ecode = GKeyTranslations.get(event.GetKeyCode(), None)
            if ecode is not None:
                self.Client.InputKeyUp(ecode)
                if self.Engine.TestMovement:
                    if ecode == engine.KEY_ARROW_LEFT:
                        self.Engine.TestMovement.Velocity.X += 8.0
                    elif ecode == engine.KEY_ARROW_RIGHT:
                        self.Engine.TestMovement.Velocity.X -= 8.0
                    elif ecode == engine.KEY_ARROW_DOWN:
                        self.Engine.TestMovement.Velocity.Y -= 8.0
                    elif ecode == engine.KEY_ARROW_UP:
                        self.Engine.TestMovement.Velocity.Y += 8.0
        self.KeyUpEvent(self, event)
        
    def HandleResize(self):
        if self.Client is None:
            return
        mouseState = wx.GetMouseState().LeftDown()
        if self.Resizing and mouseState is False:
            self.Resizing = False
            self.Client.ViewportSize = engine.FSizeI(self.Size.width, self.Size.height)
        else: 
            if self.Resizing and mouseState:
                wx.CallLater(10, self.HandleResize)

    def OnSize(self, event):
        if self.Client is None:
            return
        size = self.Size = self.GetClientSize()
        mouseState = wx.GetMouseState().LeftDown()
        if mouseState is not True:
            self.Client.ViewportSize = engine.FSizeI(self.Size.width, self.Size.height)
        else:
            if self.Resizing is not True:
                self.Resizing = True
                wx.CallLater(10, self.HandleResize)
        #event.Skip()

    def OnLeftMouseDown(self, evt):
        if self.Client is None:
            return
        self.Client.InputMouseButtonDown(engine.BUTTON_LEFT)
        self.CaptureMouse()

    def OnLeftMouseUp(self, evt):
        if self.Client is None:
            return
        self.Client.InputMouseButtonUp(engine.BUTTON_LEFT)
        if self.HasCapture():
            self.ReleaseMouse()
            
    def OnRightMouseDown(self, evt):
        if self.Client is None:
            return
        self.Client.InputMouseButtonDown(engine.BUTTON_RIGHT)
        self.CaptureMouse()
        
    def OnRightMouseUp(self, evt):
        if self.Client is None:
            return
        self.Client.InputMouseButtonUp(engine.BUTTON_RIGHT)
        if self.HasCapture():
            self.ReleaseMouse()

    def OnMouseMotion(self, evt):
        if self.Client is None:
            return
        self.Client.InputMousePosition(evt.GetX(), evt.GetY())

class CViewportFrame(wx.Frame):
    '''
    Basic frame for games. Holds a single viewport for engine rendering.
    
    Arguments:
    title -- the window title
    vpsize -- viewport size, must be sequence
    closecallback -- called when close is requested, should return True
                     to destroy the viewport and frame, False to ignore.
    '''
    def __init__(self, title, vpsize, closecallback):
        assert callable(closecallback)        
        wx.Frame.__init__(self, parent=None, title=title)
        self.CloseCallback = closecallback
        self.SetClientSizeWH(vpsize[0], vpsize[1])
        self.Resizing = False
        self.Viewport = CViewport(self)
        self.Bind(wx.EVT_CLOSE, self.OnClose)
    
    def OnClose(self, event):
        if self.CloseCallback():
            self.Hide()
            self.Viewport.Destroy()
            self.Viewport = None
            self.Destroy()